/* $Id: RankingTable.java 105 2009-05-19 21:38:08Z henk $ */
package org.jugger.tournament.gui.view;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.DefaultCellEditor;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

import org.jugger.tournament.model.Stats;
import org.jugger.tournament.model.Team;
import org.jugger.tournament.model.TeamStats;
import org.jugger.tournament.model.Tournament;
import org.jugger.tournament.model.ranking.RankingComparator;

import util.I18N;
import util.MediaManager;

/**
 * @author Sven Hamer
 */
public class RankingTable extends JTable {

	private static final long serialVersionUID = 1087517990189529308L;
	private final Tournament tournament;
	private final boolean readonly;

	public enum RankingColumn {
		RANK, TEAM, NB_MATCHES, NB_WIN, NB_DRAW, NB_LOST, POINTS_POSITIVE, POINTS_NEGATIVE, POINTS_DIFFERENCE, SCORE_POSITIVE, SCORE_NEGATIVE, SCORE_DIFFERENCE
	}

	public RankingTable(final Tournament tournament, Collection<TeamStats> ranking, Collection<TeamStats> rankingLastRound, boolean readonly) {

		this.tournament = tournament;
		this.readonly = readonly;

		setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		((DefaultCellEditor)getDefaultEditor(Integer.class)).setClickCountToStart(1);

		setRanking(ranking, rankingLastRound);

		addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				Point point = new Point(e.getX(), e.getY());

//				int columnIndex = columnAtPoint(point);
				int rowIndex = rowAtPoint(point);

				getSelectionModel().setSelectionInterval(rowIndex, rowIndex);
				final RankingTableModel model = (RankingTableModel)getModel();

				Team teamClicked = model.getTeam(rowIndex);
				if(!RankingTable.this.readonly) {
					if(e.getClickCount() > 1) {
						// edit team
						executeEditTeam(teamClicked);
					}
				}
			}
			public void mouseEntered(MouseEvent e) {
			}
			public void mouseExited(MouseEvent e) {
			}
			public void mousePressed(MouseEvent e) {
			}
			public void mouseReleased(MouseEvent e) {
			}
		});
	}

	private void executeEditTeam(Team team) {
		if(Utils.showEditTeamDialog(this, team, tournament)) {
			getRootPane().repaint();
		}
	}

	public void setRanking(Collection<TeamStats> ranking,
			Collection<TeamStats> rankingLastRound) {
		setModel(new RankingTableModel(tournament.getRankingComparator(), ranking, rankingLastRound));

		getColumnModel().getColumn(RankingColumn.RANK.ordinal()).setMinWidth(65);
		getColumnModel().getColumn(RankingColumn.RANK.ordinal()).setMaxWidth(65);
		getColumnModel().getColumn(RankingColumn.RANK.ordinal()).setCellRenderer(new RankCellRenderer());
		for(int i=1; i<this.getColumnCount(); ++i) {
			if(i != RankingColumn.TEAM.ordinal()) {
				getColumnModel().getColumn(i).setMinWidth(50);
				getColumnModel().getColumn(i).setMaxWidth(50);
			}
		}
	}

	static class RankInfo {
		public final int current;
		public final int last;

		public RankInfo(int current, int last) {
			this.current = current;
			this.last = last;
		}

		/**
		 *
		 * @return 0 if no change or first round, 1 if down in ranking, -1 if up in ranking. +/- 2 if fast.
		 */
		public int getRankChangeDirection() {
			if(last == -1)
				return 0;
			if(last == current)
				return 0;
			if(current > last) {
				if(current > last+2)
					return 2;
				return 1;
			}
			if(current+2 < last)
				return -2;
			return -1;
		}

		@Override
		public String toString() {
        	if(last == -1 || last == current) {
        		return current + "";
        	}
        	return current + " ("+last+")";
		}
	}

	static class RankCellRenderer extends DefaultTableCellRenderer {
		private static final long serialVersionUID = 6460659343435373554L;

		//	    DateFormat formatter;
	    public RankCellRenderer() {
	    	super();
   		    setHorizontalAlignment(JLabel.LEFT);
   		    setHorizontalTextPosition(SwingConstants.RIGHT);
	    }

//	    public Component getTableCellRendererComponent(JTable table,
//	    	    Object value, boolean isSelected, boolean hasFocus, int row, int column) {
//	    	return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
//	    }
	    public void setValue(Object value) {
	    	RankInfo v = (RankInfo)value;

	        switch(v.getRankChangeDirection()) {
	        case -2:
		    	setIcon(MediaManager.getImageIcon("images/rank_up_fast_small.png"));
	        	break;
	        case -1:
		    	setIcon(MediaManager.getImageIcon("images/rank_up_small.png"));
	        	break;
	        case 0:
		    	setIcon(MediaManager.getImageIcon("images/rank_stable_small.png"));
	        	break;
	        case 1:
		    	setIcon(MediaManager.getImageIcon("images/rank_down_small.png"));
	        	break;
	        case 2:
		    	setIcon(MediaManager.getImageIcon("images/rank_down_fast_small.png"));
	        	break;
	        }

	        setText(value.toString());
	    }
	}



	class RankingTableModel extends AbstractTableModel {

		private static final long serialVersionUID = 5685959044888903092L;

		private String[] columnNames = {
	    	"Rank", "Team", "Matches", "NbWin", "NbDraw", "NbLost", "PointsPositive", "PointsNegative", "PointsDifference", "ScorePositive", "ScoreNegative", "ScoreDifference"
	    };

		private RankingComparator rankingComparator;
		private ArrayList<TeamStats> ranking;
		private ArrayList<TeamStats> rankingLastRound;

	    public RankingTableModel(RankingComparator rankingComparator, Collection<TeamStats> ranking, Collection<TeamStats> rankingLastRound) {
	    	this.rankingComparator = rankingComparator;
			this.ranking = new ArrayList<TeamStats>(ranking);
			this.rankingLastRound = rankingLastRound == null ? null : new ArrayList<TeamStats>(rankingLastRound);
	    }

	    public int getColumnCount() {
	        return columnNames.length + rankingComparator.getAdditionalColumnCount();
	    }

	    public int getRowCount() {
	        return ranking.size();
	    }

	    @Override
	    public String getColumnName(int col) {
	        String name = "rankingTableColumn";
	    	if(col < columnNames.length) {
	    		name += columnNames[col];
	        }
	    	else {
	    		name += rankingComparator.getAdditionalColumnName(col - columnNames.length);
	    	}
	    	return I18N.__(name);
	    }

	    public Team getTeam(int rowIndex) {
	    	return ranking.get(rowIndex).getTeam();
	    }

	    private int calculateLastRank(Team team) {
	    	if(rankingLastRound == null)
	    		return -1;
        	for(int lastRow = 0; lastRow < rankingLastRound.size(); ++lastRow) {
        		if(rankingLastRound.get(lastRow).getTeam() == team)
        			return lastRow+1;
        	}
	    	return 0;
	    }

	    public Object getValueAt(int row, int col) {
	        TeamStats teamStats = ranking.get(row);
	        Stats stats = teamStats.getStats();

	        if(col < columnNames.length) {
		        switch(RankingColumn.values()[col]) {
		        case RANK:
		        	return new RankInfo(row+1, calculateLastRank(teamStats.getTeam()));
		        case TEAM:
		        	return teamStats.getTeam().getName();
		        case NB_MATCHES:
		        	return stats.getNbMatches();
		        case NB_WIN:
		        	return stats.getNbWin();
		        case NB_DRAW:
		        	return stats.getNbDraw();
		        case NB_LOST:
		        	return stats.getNbLost();
		        case POINTS_POSITIVE:
		        	return stats.getPointsPositive();
		        case POINTS_NEGATIVE:
		        	return stats.getPointsNegative();
		        case POINTS_DIFFERENCE:
		        	return stats.getPointsDifference();
		        case SCORE_POSITIVE:
		        	return stats.getScorePositive();
		        case SCORE_NEGATIVE:
		        	return stats.getScoreNegative();
		        case SCORE_DIFFERENCE:
		        	return stats.getScoreDifference();
		        }
		        throw new RuntimeException("Invalid ranking table column.");
	        }

	        return rankingComparator.getAdditionalColumnValue(teamStats, col - columnNames.length);
	    }

	    @Override
	    public Class<? extends Object> getColumnClass(int c) {
	    	return getValueAt(0, c).getClass();
	    }
	}
}
